﻿using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using LightCAD.MathLib;
namespace LightCAD.Core.Elements
{
    /// <summary>
    /// 双向无限的辅助线
    /// </summary>
    public class LcXLine : LcElement
    {
        public Vector2 StartPoint;
        public Vector2 prePoint;
        public Vector2 endPoint;
        public Vector2 Direction;
        public LcXLine()
        {
            this.Type = BuiltinElementType.XLine;
        }
        public LcXLine(Vector2 start, Vector2 dir)
        {
            this.StartPoint = start;
            this.Direction = dir;
            //this.prePoint = new Vector2(this.StartPoint.X - this.Direction.X * 400, this.StartPoint.Y - this.Direction.Y * 400);
            //this.endPoint = new Vector2(this.StartPoint.X + this.Direction.X * 400, this.StartPoint.Y + this.Direction.Y * 400);
        }

        public override LcElement Clone()
        {
            var clone = Document.CreateObject<LcXLine>();
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;
        }

        public override void Copy(LcElement src)
        {
            base.Copy(src);
            var line = ((LcXLine)src);
            this.StartPoint = line.StartPoint;
            this.Direction = line.Direction;
            this.prePoint = line.prePoint;
            this.endPoint = line.endPoint;
        }

        public override void Translate(Vector2 vec)
        {
            //this.StartPoint.Add(vec);
            //this.Direction.Add(vec);
            base.Translate(vec);
            /*if (this._boudingBox != null)
                this._boudingBox.Translate(vec);*/
            
        }

        public override void Translate(double dx, double dy)
        {
            //var v2 = ThreadContext.GetCurrThreadContext().Vector2.Set(dx, dy);
            //this.Translate(v2);
            base.Translate(dx, dy);
            /*if (this._boudingBox != null)
                this._boudingBox.Translate(dx, dy);*/
        }
        public void Set(Vector2 startPoint = null, Vector2 dir = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (startPoint != null) this.StartPoint = startPoint;
                if (dir != null) this.Direction = dir;
            }
            else
            {
                bool chg_start = (startPoint != null && startPoint != this.StartPoint);
                if (chg_start)
                {
                    //OnPropertyChangedBefore(nameof(StartPoint), this.StartPoint, startPoint);
                    var oldValue = this.StartPoint;
                    this.StartPoint = startPoint;
                    OnPropertyChangedAfter(nameof(StartPoint), oldValue, this.StartPoint);
                }
                bool chg_end = (dir != null && dir != this.Direction);
                if (chg_end)
                {
                    //OnPropertyChangedBefore(nameof(Direction), this.Direction, dir);
                    var oldValue = this.Direction;
                    this.Direction = dir;
                    OnPropertyChangedAfter(nameof(Direction), oldValue, this.Direction);
                }
            }
        }

        public override Box2 GetBoundingBox()
        {
            Vector2 start = new Vector2();
            Vector2 end = new Vector2();
            if (this.Direction.Y == 0)
            {
                start.X = -(this.Direction.X * double.MaxValue);
                start.Y = this.StartPoint.Y;
                end.X = this.Direction.X * double.MaxValue;
                end.Y = this.StartPoint.Y;
            }
            else if (this.Direction.X == 0)
            {
                start.X = this.StartPoint.X;
                start.Y = -(this.Direction.Y * double.MaxValue);
                end.X = this.StartPoint.X;
                end.Y = this.Direction.Y * double.MaxValue;
            }
            else
            {
                start = -(this.Direction * double.MaxValue);
                end = this.Direction * double.MaxValue;
            }
            return new Box2().SetFromPoints(start, end);
        }

        /*public override Box2 GetBoundingBox()
        {
            this.prePoint = new Vector2(this.StartPoint.X - this.Direction.X * 400, this.StartPoint.Y - this.Direction.Y * 400);
            this.endPoint = new Vector2(this.StartPoint.X + this.Direction.X * 400, this.StartPoint.Y + this.Direction.Y * 400);
            Vector2 start = new Vector2();
            Vector2 end = new Vector2();
            if (this.Direction.Y == 0)
            {
                start.X = this.prePoint.X;
                start.Y = this.StartPoint.Y;
                end.X = this.endPoint.X;
                end.Y = this.StartPoint.Y;
            }
            else if (this.Direction.X == 0)
            {
                start.X = this.StartPoint.X;
                start.Y = this.prePoint.Y;
                end.X = this.StartPoint.X;
                end.Y = this.endPoint.Y;
            }
            else
            {
                start = this.prePoint;
                end = this.endPoint;
            }
            return new Box2().SetFromPoints(start, end);
        }*/

        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                //如果元素盒子，与多边形盒子不相交，那就可能不相交
                return false;
            }
            return LcGeoUtils.IsPolygonIntersectXLine(testPoly.Points, this);
        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            return false; //射线不可能被某一个包围盒完全包含
        }

        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            writer.WriteVector2dProperty(nameof(this.StartPoint), this.StartPoint);
            writer.WriteVector2dProperty(nameof(this.Direction), this.Direction);
        }
        public override void ReadProperties(ref JsonElement jele)
        {
            this.StartPoint = jele.ReadVector2dProperty(nameof(StartPoint));
            this.Direction = jele.ReadVector2dProperty(nameof(Direction));
        }

        public override List<Vector2> GetCrossVectorByLine(Line2d line2D)
        {
            List<Vector2> points = new List<Vector2>();
            Vector2 endpoint = new Vector2();
            endpoint = this.Direction * 8 + this.StartPoint;
            // 定义第一条线段的起点和终点坐标
            double x1 = this.StartPoint.X;
            double y1 = this.StartPoint.Y;
            double x2 = endpoint.X;
            double y2 = endpoint.Y;

            // 定义第二条线段的起点和终点坐标
            double x3 = line2D.Start.X;
            double y3 = line2D.Start.Y;
            double x4 = line2D.End.X;
            double y4 = line2D.End.Y;

            // 计算交点的坐标
            Vector2 point = new Vector2();
            point.X = ((x3 * y4 - x4 * y3) * (x2 - x1) - (x1 * y2 - x2 * y1) * (x4 - x3)) /
                                  ((y1 - y2) * (x4 - x3) - (y3 - y4) * (x2 - x1));

            point.Y = ((y3 * x4 - y4 * x3) * (y2 - y1) - (y1 * x2 - y2 * x1) * (y4 - y3)) /
                                 ((x1 - x2) * (y4 - y3) - (x3 - x4) * (y2 - y1));

            if (point != null)
            {
                if (GeoUtils.IsPointOnLineExtension(line2D.Start, line2D.End, point))
                {
                    return null;
                }
                else
                {
                    points.Add(point);
                    return points;

                }
            }
            else
            {
                return null;
            }
        }

        public override List<Vector2> GetCrossVectorByArc(Arc2d arc)
        {
            // 定义第一条线段的起点和终点坐标
            Vector2 endpoint = new Vector2();
            endpoint = this.Direction * 8 + this.StartPoint;


            Arc2d arc2D = new Arc2d();
            arc2D.Startp = arc.Startp;
            arc2D.Endp = arc.Endp;
            arc2D.Center = arc.Center;
            arc2D.Radius = arc.Radius;
            arc2D.StartAngle = arc.StartAngle;
            arc2D.EndAngle = arc.EndAngle;
            arc2D.IsClockwise = false;

            List<Vector2> points = GeoUtils.GetCrossLineArc(this.StartPoint, endpoint, arc2D.Center, arc2D.Radius);
            return points;
            //List<Vector2> endpoints = new List<Vector2>();
            //foreach (var item in points)
            //{
            //    if (!Arc2d.PointInArc(item, arc2D.Startp, arc2D.Endp, arc2D.Center))
            //    {
            //        endpoints.Add(item);
            //    }
            //}
            //return endpoints;
            //return GeoUtils.ArcCrossLine(arc2D, line1);
        }
    }
}